﻿#pragma once
#include "MuType.h"
#include "MuEncDec.h"
#include "TcpClient.h"

class MuNetConnect : protected TcpClient::Listener
{
public:
    class Listener
    {
    public:
        virtual void on_cs_connect(bool status) {}
        virtual void on_cs_close() {}
        virtual void on_cs_firstResponse() {}
        virtual void on_cs_serverList(MuPack::ServerList* serverList) {}
        virtual void on_cs_serverAddr(MuPack::ServerAddr* serverAddr) {}

        virtual void on_gs_connect(bool status) {}
        virtual void on_gs_close() {}
        virtual void on_gs_gameObjIdAndVersion(MuPack::GameObjIdAndVersion* gameObjId) {}
        virtual void on_gs_loginResult(u_char status) {}
        virtual void on_gs_characterList(MuPack::CharacterList* characterList) {}
        virtual void on_gs_moveNotice(MuPack::MoveNotice* moveNotice) {}
        virtual void on_gs_placePlayer(MuPack::PlacePlayer* placePlayer) {}
        virtual void on_gs_placeMonster(MuPack::PlaceMonster* placeMonster) {}
        virtual void on_gs_removeTarget(MuPack::RemoveTarget* removeTarget) {}
        virtual void on_gs_changeDir(MuPack::ChangeDir *changeDir) {}
        virtual void on_gs_setCurrLife(size_t currLife) {}
        virtual void on_gs_setCurrMana(size_t currMana) {}
        virtual void on_gs_characterInfo(MuPack::CharacterInfo* charInfo) {}
    };

private:
	MuNetConnect();

public:
	~MuNetConnect();
	static MuNetConnect *GetInstance();
	static void Destroy();

    void setListener(Listener* listener) {
        m_listener = listener;
    }

    bool isConnected_cs() {
        return m_cs.isConnected();
    }

    bool isConnected_gs() {
        return m_gs.isConnected();
    }

    // 使用cs
    void connectCs(const char* host, u_short port);
    void RequestServerList();
    void RequestServerAddr(u_char code);

    // 使用gs
    void connectGs(const char* host, u_short port);
    void Login(char *username, char *password);
    void RequestCharacterList();
    void CreateCharacter(char *name, MuType::CharacterClass mucls);
    void DeleteCharacter(char *name);
    void StartPlaying(char *name);

    void SendCheckSum(int key);
    void SendTick();
    void SendMapDir(u_char dir);
    void SendMovePosDirs(POINT &start, std::vector<u_char> &dirs);
    void Attack(u_short id, u_char dir);


protected:
    static MuNetConnect *s_inst;
    TcpClient m_cs;
    TcpClient m_gs;
    int m_cs_id = 1;
    int m_gs_id = 2;
    Listener* m_listener = nullptr;
    uv_timer_t m_timerTick;

    static const int s_max_tempBuf = 0x10000;
    unsigned char m_tempBuf[s_max_tempBuf];
    MuEncDec m_encDec;
    void send(TcpClient& sock, void* data, size_t dataLen, bool encode);

    static void on_timer(uv_timer_t* handle);
    void setTick(bool run);

    // 解包收到的数据，函数返回包长度，引用参数返回包数据地址和长度
    size_t unpacket(u_char *data, size_t dataLen, u_char*& outPackData, size_t& outPackDataLen);
    void dispatchPacket_cs(u_char* data, size_t dataLen);
    void dispatchPacket_gs(u_char* data, size_t dataLen);

    // 通过 Listener 继承
    virtual void on_connect(TcpClient * sock, int status) override;
    virtual void on_close(TcpClient * sock) override;
    virtual size_t on_read(TcpClient * sock, char * data, size_t dataLen) override;

public:
	char *m_clientVersion;
	char *m_verificationString;
	std::string m_cs_ip;
	std::string m_gs_ip;
	unsigned short m_cs_port;
	unsigned short m_gs_port;
	WORD m_gameObjId;
	char m_serverVersion[4];
	int m_gs_serverCode;
	struct
	{
		char name[12];
		int level;
		MuType::CharacterClass muCls;
	}m_currCharacter;

};

